/**
 * @file .
 * @author wangxiaowei0303@163.com
 */

#include <algorithm>
#include <opencv2/imgproc/imgproc.hpp>

#include "AdaptiveMFilter.h"
#include "../string_util.h"


/* this->maxTimes 呈现给用户的名称. */
#define MAX_TIMES "max-times"

void 
AdaptiveMFilter::help(std::string &buf) const
{
    buf.append(
        "自适应中值滤波器.\n"
        MAX_TIMES";指定了滤波器最多可以扩展边界的次数.\n"
        "row,col;滤波器最初的行,列数.\n"
    );
    return ;
}

void
AdaptiveMFilter::set(const char *argname,const char *argval)
{
    if (strEqual(argname,MAX_TIMES)) 
        this->maxTimes = strtoul(argval,0,0);
    else 
        Filter::set(argname,argval);
    return ;
}

const char*
AdaptiveMFilter::get(const char *argname,std::string &buf) const
{
    size_t oldSize = buf.size();
    if (strEqual(argname,MAX_TIMES)) 
        addFormat(buf,"%u",this->maxTimes);
    else 
       return Filter::get(argname,buf);
    return buf.data() + oldSize;
}

void
AdaptiveMFilter::getSupportedArgs(
    std::vector<std::string> &args) const
{
    args.push_back(MAX_TIMES);
    Filter::getSupportedArgs(args);
    return ;
}

double
AdaptiveMFilter::operOnNeigh(const cv::Mat &neigh)
{
    unsigned int times = 0;
    cv::Mat tmp;
    /*
     * 这里虽然去除了 neigh 的 const 属性,但是并没有修改 neigh.data 指向内存
     * 的内容,此时可能修改了 neigh.rows,neigh.cols,等一些域的值.
     */
    cv::Mat &m1 = const_cast<cv::Mat&>(neigh);
    uchar zmin,zmax,zmed;
    const uchar zxy = neigh.at<uchar>((neigh.rows - 1)/2,(neigh.cols - 1)/2);

    while (true) {
        /*
         * 在每一次进入循环,times 表明当前已经扩展邻域的次数.
         */
        tmp = m1.clone();
        std::sort(tmp.begin<uchar>(),tmp.end<uchar>());
        cv::MatConstIterator_<uchar> iter = tmp.begin<uchar>();
        zmin = *iter;
        zmax = *(iter + tmp.total() - 1);
        zmed = *(iter + (tmp.total() - 1) / 2);
        if (times > maxTimes) 
            return zmed;
        if (zmed < zmax && zmed > zmin) {
            if (zxy < zmax && zxy > zmin) 
                return zxy;
            else
                return zmed;
        } else {
            ++times;
            m1.adjustROI(1,1,1,1);
        }
    }
    return 33;/* 不会被执行到 */
}

cv::Mat
AdaptiveMFilter::makeBorder(const cv::Mat &m,int &t,int &b,int &l,int &r)
{
    t = b = (this->row - 1) / 2 + this->maxTimes + 1;
    l = r = (this->col - 1) / 2 + this->maxTimes + 1;
    cv::Mat m1(m.rows + t + b,m.cols + r + l,CV_8UC1);
    cv::copyMakeBorder(m,m1,t,b,l,r,cv::BORDER_REPLICATE);
    return m1;
}

NOISE_ALGO_REGISTER("AdaptiveMFilter",AdaptiveMFilter);
